package han.cirno.corrupt.compose

import android.annotation.SuppressLint
import android.content.Context
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.datastore.preferences.core.edit
import han.cirno.corrupt.Application
import han.cirno.corrupt.dataStore
import han.cirno.corrupt.getPreferenceKey
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.util.Locale

val LocalLocaleContext= staticCompositionLocalOf<Context> { error("No context found") }

@Composable
fun TextWithIcon(
    modifier: Modifier = Modifier,
    iconRes: Int,
    text: String,
    style:TextStyle=MaterialTheme.typography.bodyMedium
){
    Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) {
        Icon(
            modifier = Modifier.width(24.dp).fillMaxHeight(),
            painter = painterResource(iconRes),
            contentDescription = null)
        Spacer(modifier = Modifier.width(8.dp))
        Text(text = text, style=style)
    }
}

@Composable
fun TitleTextWithIcon(
    modifier: Modifier = Modifier,
    iconRes: Int,
    textRes: Int
)= TextWithIcon(
    modifier = modifier, iconRes,
    localeStringResource(textRes), style = MaterialTheme.typography.titleMedium
)

@Composable
fun QuickCard(modifier: Modifier=Modifier,content:@Composable ColumnScope.()->Unit){
    Card(modifier = Modifier
        .fillMaxWidth()
        .padding(0.dp, 4.dp),
        elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)) {
        Column(modifier = modifier
            .padding(16.dp)
            .fillMaxWidth(), content = content)
    }
}

@Composable
fun QuickOutlinedCard(
    @SuppressLint("ModifierParameter") modifier: Modifier=Modifier
        .fillMaxWidth()
        .padding(0.dp, 4.dp),
    onClick:(()->Unit)?=null, content:@Composable ColumnScope.() -> Unit){
    val elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
    val innerContent:@Composable ColumnScope.()->Unit= {
        Column(modifier = Modifier
            .padding(16.dp)
            .fillMaxWidth(), content = content)
    }
    if (onClick==null)
        OutlinedCard(modifier=modifier, elevation = elevation, content = innerContent)
    else
        OutlinedCard(modifier=modifier, elevation = elevation, content = innerContent, onClick = onClick)
}

@Composable
fun VerticalSpacer(height:Dp){
    Spacer(modifier = Modifier
        .fillMaxWidth()
        .height(height))
}

@Composable
fun SimpleRadioButton(text:Int,num:Int,state:MutableState<Int>){
    var stateInt by state
    Row(
        Modifier
            .clickable { stateInt = num }
            .padding(vertical = 8.dp, horizontal = 4.dp)
            .fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically){
        RadioButton(selected = num==stateInt, onClick = null)
        Spacer(modifier = Modifier.width(8.dp))
        Text(text= localeStringResource(text))
    }
}

@Composable
fun SimpleTextPair(textLeft: String,textRight:String){
    if ("_Nullity_" in textRight)return
    Row(modifier = Modifier.fillMaxWidth()) {
        Text(text=textLeft)
        Text(modifier = Modifier.weight(1f), text=textRight, textAlign = TextAlign.End)
    }
}

fun Context.updateLocale(locale: Locale):Context=
    createConfigurationContext(
        resources.configuration.apply{setLocale(locale)}
    )

@Composable
fun localeStringResource(resId:Int,vararg formatArgs: Any):String=
    LocalLocaleContext.current.resources.getString(resId,*formatArgs)


inline fun <reified I,O> preferenceFlow(
    keyString: String,
    defaultValue: I,
    crossinline readMap:(I)->O): PrefFlow<O> {
    val flow=Application.application.dataStore.data
        .map { readMap(it[getPreferenceKey<I>(keyString)]?:defaultValue) }
    return flow.wrapToPrefFlow(readMap(defaultValue), runBlocking { flow.firstOrNull()?:readMap(defaultValue)})
}

inline fun <reified T> preferenceFlow(
    keyString: String,
    defaultValue: T):PrefFlow<T> =
    preferenceFlow(keyString,defaultValue) { it }

@Composable
inline fun <reified T> rememberPreference(
    key: String,
    defaultValue: T,
    scope: CoroutineScope = rememberCoroutineScope()
): MutableState<T> {
    val state = remember(key) { mutableStateOf(defaultValue) }
    val flow = remember(key) {
        Application.application.dataStore.data
            .map { preferences -> preferences[getPreferenceKey(key)] ?: defaultValue }
            .distinctUntilChanged()
    }
    LaunchedEffect(key) {
        flow.collect { newValue -> state.value = newValue }
    }
    return object : MutableState<T> {
        override var value: T
            get() = state.value
            set(value) {
                state.value = value
                scope.launch(Dispatchers.IO) {
                    Application.application.dataStore.edit { preferences ->
                        preferences[getPreferenceKey(key)] = value
                    }
                }
            }
        override fun component1() = value
        override fun component2(): (T) -> Unit = { newValue -> value = newValue }
    }
}

fun <T> Flow<T>.wrapToPrefFlow(defaultValue: T,firstValue: T?):PrefFlow<T> =
    PrefFlow(this,defaultValue,firstValue)

class PrefFlow<O>(
    private val flow: Flow<O>,
    private val defaultValue: O,
    private val firstValue:O?
):Flow<O> by flow{
    @Composable
    fun collectAsState():State<O> =flow.collectAsState(firstValue?:defaultValue)
}